<template>
  <div @contextmenu="Contextmenu.open($event, undefined, -1, false)" style="height: 100%; overflow: hidden; width: 100%" tabindex="0">
    <div style="display: flex; align-items: center">
      <div class="negative">
        <div v-for="(item, index) in negatives" class="negative--item">
          <span @click="Root.changeFilePath(item, index)">
            {{ item.title }}
          </span>
          /
        </div>
      </div>
      <div class="flex input-wrapper">
        <input class="input" v-model="Search.context" :placeholder="`在${negatives.at(-1)?.title}中搜索`" />
        <div v-ripple class="flex input--icon">
          <v-icon v-if="Search.context" :icon="mdiClose" @click="Search.clear" />
          <v-icon v-else :icon="mdiMagnify" />
        </div>
      </div>
    </div>
    <div @wheel="Root.wheel" ref="container" class="table__wrapper">
      <table style="" class="table">
        <thead class="header">
          <tr class="header--tr">
            <th v-for="(column, index) in columns" :class="`header--column ${index !== columns.length - 1 && index && 'header--column__separated'}`">
              <div style="display: flex; text-align: start !important; padding-left: 0.5rem">
                {{ column.title }}
              </div>
            </th>
          </tr>
        </thead>
        <table-body-template />
      </table>
      <div style="display: flex; justify-content: center">
        <!--        <LoadingOutlined v-if="loading" />-->
      </div>
    </div>
    <div style="white-space: nowrap">{{ total }}个项目</div>
  </div>
  <explorer-contextmenu ref="explorerContextmenuRef" :table-module="Table" @menuclick="Contextmenu.menuclick" />
</template>
<script setup lang="tsx">
import { mdiChevronDown, mdiChevronRight, mdiClose, mdiFolder, mdiFolderOpen, mdiMagnify } from "@mdi/js";
import dayjs, { Dayjs } from "dayjs";
import { cloneDeep, debounce, isNil } from "lodash-unified";
import ExplorerContextmenu from "@/components/windows/components/Explorer/ExplorerContextmenu.vue";
const explorerContextmenuRef = useTemplateRef("explorerContextmenuRef");
const props = withDefaults(
  defineProps<{
    data: any[];
    negatives: any[];
    columns?: any[];
    total: number;
    rootFile?: any;
  }>(),
  {
    columns: () => [
      {
        dataKey: "expand",
      },
      {
        dataKey: "filename",
        title: "名称",
      },
      {
        dataKey: "twjzlTagList",
        title: "标签",
        type: "tag",
      },
      {
        dataKey: "updateTime",
        title: "修改日期",
      },
      {
        dataKey: "zlx",
        title: "类型",
      },
      {
        dataKey: "dxDw",
        title: "文件大小",
      },
    ],
    total: 0,
  },
);
const emits = defineEmits([
  "loadData",
  "openFolder",
  "expandFolder",
  "search",
  "rename",
  "delete",
  "add",
  "newFolder",
  "cut",
  "paste",
  "changeFilePath",
  "TagMana",
  "download",
  "view",
]);
const loading = defineModel("loading", {
  default: false,
});
const container = ref<HTMLElement | null>(null);
const RowTemplate = (row: any, index: number, isChild: boolean = false, parent?: any) => (
  <>
    <tr
      onContextmenu={(e) => explorerContextmenuRef.value?.open(e, row, index, isChild, parent)}
      class={`tbody--row-default ${Table.getActiveRowClass(index, isChild, row, parent ?? Table)} ${isChild && "tbody--row__border"}`}
      onDblclick={() => Table.dblclick(row)}
    >
      <td style="width: 1rem">{Table.isFolder(row) && <v-icon icon={row.expanded ? mdiChevronDown : mdiChevronRight} v-ripple onClick={(e) => Table.expandFolder(e, row)} />}</td>
      {CellTemplate(row, isChild, index, parent)}
    </tr>
    {row.children && row.expanded && row.children.map((child: any, index: number) => RowTemplate(child, index, true, row))}
  </>
);
const folderIcon = (row, index) => {
  return index === 0 && Table.isFolder(row) && <v-icon icon={row.expanded ? mdiFolderOpen : mdiFolder} />;
};
const getCellData = (row, column) => {
  if (column.type === "tag") {
    return row[column.dataKey].map((it) => <a-tag>{it.filename}</a-tag>);
  }
  return row[column.dataKey];
};
const CellTemplate = (row: any, isChild: boolean, rowIndex: number, parent?: any) =>
  props.columns
    .filter((item) => item.dataKey !== "expand")
    .map((column, index) => (
      <td onClick={() => Table.rowClick(row, rowIndex, isChild, column, parent)}>
        <div class="flex" style="padding: 1rem;width: 100%; user-select: none;">
          {isChild && index === 0 && <div style="width: 1rem;"></div>}
          {folderIcon(row, index)}
          {Rename.is_editable(row, column) ? (
            <input id="editname__input" v-model={row.filename} autofocus class="editname__input" onBlur={() => Rename.saveEditName(row)} onFocus={Rename.focus} />
          ) : (
            getCellData(row, column)
          )}
        </div>
      </td>
    ));
const TableBodyTemplate = () => <tbody class="tbody">{props.data.map((row, index) => RowTemplate(row, index))}</tbody>;
const Rename = (() => {
  const trigger = (payload:any) => {
    console.log(payload)
    // s.id = currentItem.id;
    // s.editable = true;
  };
  const saveEditName = (row) => {
    s.id = "";
    s.editable = false;
    if (s.originalName === row.filename) {
      return;
    }
    emits("rename", row);
    s.originalName = "";
  };
  //更新文件列表的时候需要调这个函数
  const reset = () => {
    s.id = "";
    s.editable = false;
    s.originalName = "";
  };
  const is_editable = (row, column) => row.id === s.id && column.dataKey === "filename" && s.editable;
  const showInput = (column, row) => {
    if (!s.lastClickTime) {
      s.lastClickTime = dayjs();
    }
    //切换点击的行时重置状态,因此需要重新记录上次单击的时间
    if (s.id !== row.id) {
      s.lastClickTime = dayjs();
      reset();
      s.id = row.id;
      return;
    }
    //如果不是名称字段则不启用重命名
    if (column.dataKey !== "filename") {
      return;
    }
    if (dayjs().diff(s.lastClickTime, "second") < 0.2) {
      return;
    }
    s.editable = true;
    s.originalName = row.filename;
    s.lastClickTime = null;
  };
  //在iframe里面此函数没效果
  const focus = (e) => {
    e.target.select();
  };
  const s = reactive({
    id: "",
    editable: false,
    originalName: "",
    ref: {
      value: null as HTMLElement | null,
      set: (value: any) => {
        s.ref.value = value;
      },
    },
    lastClickTime: null as null | Dayjs,
    saveEditName,
    showInput,
    focus,
    is_editable,
    reset,
    trigger,
  });
  return s;
})();
const Contextmenu = (() => {
  const menuclick = ( item ) => {
    emits(item.type, item.value)
  };
  const open = (e, item: any = null, index: number, isChild: boolean, parent?: any) => {
    Rename.editable = false;
    explorerContextmenuRef.value?.open(e, item, index, isChild, parent);
  };
  const s = reactive({
    open,
    menuclick
  });
  return s;
})();
const KeyBoard = (() => {
  const keyboardPressTable: Record<string, () => void> = {
    //控制选中行向下
    ArrowDown: () => {
      //如果没有任何选中行
      let first = Table.activatedIds[0];
      if (isNil(first)) {
        first = 0;
        Table.activatedIds = [first];
        return;
      }
      //如果是最后一个元素
      if (first === props.data.length - 1) {
        Table.activatedIds = [0];
        return;
      }
      Table.activatedIds = [first + 1];
    },
    //控制选中行向上
    ArrowUp: () => {
      let last = Table.activatedIds.at(-1);
      if (isNil(last) || last === 0) {
        last = props.data.length - 1;
        Table.activatedIds = [last];
        return;
      }
      Table.activatedIds = [last - 1];
    },
    Control: () => {
      s.pressed.ctrl = true;
    },
  };
  const listener = {
    keydown: (enter: KeyboardEvent) => {
      const fn = keyboardPressTable[enter.key];
      fn && fn();
    },
    keyup: (enter: KeyboardEvent) => {
      if (enter.key === "Control") {
        s.pressed.ctrl = false;
        delete s.pressed.ctrl;
      }
    },
  };
  const registerListener = () => {
    const keys = Object.keys(listener);
    keys.forEach((key) => {
      addEventListener(key, listener[key]);
      onUnmounted(() => {
        removeEventListener(key, listener[key]);
      });
    });
  };
  const decideShortcutKey = (keys: string[], number: number) => {
    if (Object.keys(s.pressed).length !== number) return false;
    for (const key of keys) {
      if (!s.pressed[key]) return false;
    }
    return true;
  };
  const s = reactive({
    pressed: {} as any,
    decideShortcutKey,
  });
  registerListener();
  return s;
})();

const Table = (() => {
  type ISelected = {
    id: string;
  }
  const rowSelect = (index: number, parent: any, isChild: boolean) => {
    if (isChild) {
      s.activatedIds = [];
    }
    if (KeyBoard.decideShortcutKey([], 0)) {
      parent.activatedIds = [index];
    }
    if (KeyBoard.decideShortcutKey(["ctrl"], 1)) {
      if (parent.activatedIds.includes(index)) {
        parent.activatedIds = parent.activatedIds.filter((item) => item !== index);
      } else {
        parent.activatedIds.push(index);
      }
    }
  };
  const getActiveRowClass = (index: number, isChild: boolean, row: any, parent?: any) => {
    const is_activate = parent.activatedIds.includes(index);
    if (s.cutList.includes(row.id) && !is_activate) {
      return " row__cut ";
    } else {
      return is_activate ? "is_activate" : "row";
    }
  };
  const rowClick = (row: any, index: number, isChild: boolean = false, column, parent?: any) => {
    Rename.showInput(column, row);
    if (parent) {
      rowSelect(index, parent, true);
    } else {
      rowSelect(index, s, false);
    }
  };
  const isFolder = (row: any) => row.lx === 0;
  const openFolder = (row: any) => {
    if (!isFolder(row)) return;
    s.activatedIds = [];
    Rename.reset();
    emits("openFolder", row);
  };
  const dblclick = (row: any) => {
    if (row.lx === 0) {
      openFolder(row);
    } else {
      emits("view", row);
    }
  };
  const expandFolder = (e: any, row: any) => {
    /*    e.stopPropagation();
    row.expanded = !row.expanded;
    emits("expandFolder", row);*/
  };
  const s = reactive({
    activatedIds: [] as number[],
    selected: {} as Record<string, ISelected>,
    cutList: [] as string[],
    expandFolder,
    rowClick,
    dblclick,
    isFolder,
    getActiveRowClass,
  });
  return s;
})();
const Search = (() => {
  const setWatcher = () => {
    watch(
      () => s.context,
      () => {
        if (s.emitTimer) {
          clearTimeout(s.emitTimer);
        }
        s.emitTimer = setTimeout(() => {
          Rename.reset();
          emits("search", s.context);
          s.emitTimer = null;
        }, 500);
      },
    );
  };
  const clear = () => {
    s.context = "";
  };
  const s = reactive({
    context: "",
    emitTimer: null as null | number,
    clear,
  });
  setWatcher();
  return s;
})();
const Root = (() => {
  const changeFilePath = (item, index) => {
    emits("changeFilePath", item, index);
  };
  //鼠标滑轮事件 下滑触发加载数据
  const wheel = debounce((e) => {
    s.wheelToward = e.deltaY > 0 ? "down" : "up";
    if (loading.value) return;
    const { scrollTop, clientHeight, scrollHeight } = container.value!;
    const noScrollbar = scrollHeight >= clientHeight;
    if (scrollTop + clientHeight < scrollHeight - 10) return;
    //如果是最后一页 就不请求数据
    if (s.loadCount === s.scrollCount) return;
    if (noScrollbar && s.wheelToward === "down") {
      loading.value = true;
      s.loadCount++;
      emits("loadData");
    }
  }, 200);
  const s = reactive({
    loadCount: 1,
    scrollCount: computed(() => Math.ceil(props.total / 10)),
    wheelToward: "" as "up" | "down",
    wheel,
    changeFilePath,
  });
  return s;
})();
</script>

<style scoped lang="scss">
:deep() {
  .flex {
    display: flex;
    align-items: center;
  }

  .negative {
    border: 1px solid;
    width: 300%;
    height: 2rem;
    display: flex;
    align-items: center;
    font-size: 14px;
    &--item:hover {
      background: #cae9f6;
      cursor: pointer;
    }
  }
  .table__wrapper {
    height: 40rem;
    overflow: auto;

    .table {
      width: 100%;
      margin-top: 1rem;
    }
  }

  .header {
    &--column:hover {
      background: #cae9f6;
    }
    &--column__separated {
      border-right: 1px solid #e8e1e1;
    }
  }

  .tbody {
    &--row-default {
      box-sizing: border-box;
      border: 1px solid transparent;
      border-bottom: none;
      font-size: 14px;
    }

    &--row-child-default {
    }
  }

  .row {
    height: 100%;
  }

  .row:hover {
    background: #cae9f6;
  }

  .row__cut {
    background: #e0e4ec;
  }

  .row__cut:hover {
    background: #cae9f6;
  }

  .is_activate {
    box-sizing: border-box;
    background: #cae9f6;
    border: #47c0f4 1px solid;
  }

  .input-wrapper {
    border: 1px solid;
    height: 2rem;
    margin-left: 1rem;
    width: 100%;

    .input {
      height: 100%;
      width: 100%;
      outline: none;
      padding-left: 1rem;

      &--icon {
        color: #5a5e66;
        height: 90%;
        width: 1.8rem;
        justify-content: center;
        margin-right: 0.2rem;
      }

      &--icon:hover {
        border: 1px solid #47c0f4;
        background: #e6f6ff;
      }
    }
  }

  .input-wrapper:hover {
    border-color: #47c0f4;
  }

  .input-wrapper:focus-within {
    border-color: #47c0f4;
  }

  .editname__input {
    outline: none;
    width: 100%;
    border: 1px solid;
    height: 100%;
  }
}
</style>
